package com.fafian.gdc.socket;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

import com.fafian.gdc.core.BusCommand;
import com.fafian.gdc.core.Source;
import com.fafian.publish.PublishBus;


public class SocketController extends Thread implements Runnable {

	private PublishBus bus;
	private ServerSocket ss;
	private String apiKey;
	private boolean run;
	
	public SocketController(PublishBus bus, int socketPort, String apiKey) throws IOException{
		ss = new ServerSocket(socketPort);
		this.bus = bus;
		this.apiKey = apiKey;
		setName("SocketControllerThread");
		run = true;
	}
	
	public void stopController(){
		run = false;
	}
	
	
	
	private SocketMessageResponse publishRequest(SocketMessageRequest request, HashMap<String, String> extraInfo){
		if (!apiKey.equals(request.getApiKey())){
			return new SocketMessageResponse(false, "Forbidden");
		}
		BusCommand bc = new BusCommand(request.getCommand(), Source.SOCKET, extraInfo);
		bus.publish(bc);
		return new SocketMessageResponse(true, "OK");
	}
	
	
	public void run(){
		try{
			while (run){
				GDCSocket socket= null;
				try {
					
					Socket s = ss.accept();
					HashMap<String, String> extraInfo = new HashMap<String, String>();
					System.out.println("Received connection "+s.getRemoteSocketAddress().toString());
					extraInfo.put("remoteAddress", s.getRemoteSocketAddress().toString());
					socket = new GDCSocket(s);
					
					SocketMessage message = socket.getIncomingMessage();
					switch (message.getType()){
					case REQUEST:
						socket.sendMessage(publishRequest((SocketMessageRequest) message, extraInfo));
						socket.close();
						break;
					case RESPONSE:
						socket.sendMessage(new SocketMessageResponse(false, "Request Format Incorrect: received response instead of request"));
						socket.close();
						break;
					case UNKNOWN:
						socket.sendMessage(new SocketMessageResponse(false, "Request Format Incorrect: format unknown"));
						socket.close();
						break;
					default:
						socket.sendMessage(new SocketMessageResponse(false, "Internal error"));
						socket.close();
						break;
					
					}
					
				} catch (IOException e) {
					e.printStackTrace();
				} catch (GDCSocketException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				finally{
					try {
						if (socket!=null)
							socket.close();
					} catch (GDCSocketException e) {
						e.printStackTrace();
					}
				}
				
			}
		}
		finally{
			try {
				ss.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	
}
